/**********************************************************************************************************************
 * \file Cpu0_Main.c
 * \copyright Copyright (C) Infineon Technologies AG 2019
 * 
 * Use of this file is subject to the terms of use agreed between (i) you or the company in which ordinary course of 
 * business you are acting and (ii) Infineon Technologies AG or its licensees. If and as long as no such terms of use
 * are agreed, use of this file is subject to following:
 * 
 * Boost Software License - Version 1.0 - August 17th, 2003
 * 
 * Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and 
 * accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute,
 * and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the
 * Software is furnished to do so, all subject to the following:
 * 
 * The copyright notices in the Software and this entire statement, including the above license grant, this restriction
 * and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all 
 * derivative works of the Software, unless such copies or derivative works are solely in the form of 
 * machine-executable object code generated by a source language processor.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 
 * COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN 
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
 * IN THE SOFTWARE.
 *********************************************************************************************************************/
/*\title Multicore LED control
 * \abstract One LED is controlled by using three different cores.
 * \description Core 0 is switching on an LED. When the LED flag is set, Core 1 is switching off the LED.
 *              Core 2 is controlling the state of the LED flag.
 *
 * \name Multicore_1_KIT_TC297_TFT
 * \version V1.0.0
 * \board APPLICATION KIT TC2X7 V1.1, KIT_AURIX_TC297_TFT_BC-Step, TC29xTA/TX_BC-step
 * \keywords multicore, LED, AURIX, Multicore_1
 * \documents https://www.infineon.com/aurix-expert-training/Infineon-AURIX_Multicore_1_KIT_TC297_TFT-TR-v01_00_00-EN.pdf
 * \documents https://www.infineon.com/aurix-expert-training/TC29B_iLLD_UM_1_0_1_11_0.chm
 * \lastUpdated 2020-02-11
 *********************************************************************************************************************/
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"
#include "hDrv.h"

#include <netif.h>
#include <tcpip.h>
#include <etharp.h>
#include <ethernet.h>
#include <ethernetif.h>
#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/netif.h"
#include "lwip/timeouts.h"
#include "string.h"
#include "sockets.h"
#include "udp.h"
#include "ip4_addr.h"

IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define HEARTBEAT_TASK_PRIORITY 3

#define UDP_SERVER_PORT 8080
int ddddd_flag = 0;
static struct netif xnetif =
    {
        /* set MAC hardware address length */
        .hwaddr_len = (u8_t)ETH_HWADDR_LEN,

        /* set MAC hardware address */
        .hwaddr = {0x00, 0x20, 0x30, 0x40, 0x50, 0x60},

        /* maximum transfer unit */
        .mtu = 1500U,
};

#define ISR_PRIORITY_ETH_IRQ 3

static void net_init(void)
{
    ip_addr_t ipaddr;
    ip_addr_t netmask;
    ip_addr_t gw;

    Ifx_print("net_init no dhcp\r\n");
    IP4_ADDR(&ipaddr, 192, 168, 5, 123);
    IP4_ADDR(&netmask, 255, 255, 255, 0);
    IP4_ADDR(&gw, 192, 168, 5, 1);

    /* Create tcp_ip stack thread */
    Ifx_print("net_init \r\n");
    lwip_init();
    //tcpip_init(NULL, NULL);
    Ifx_print("net_init tcpip_init down \r\n");

    /* - netif_add(struct netif *netif, struct ip_addr *ipaddr,
  struct ip_addr *netmask, struct ip_addr *gw,
  void *state, err_t (* init)(struct netif *netif),
  err_t (* input)(struct pbuf *p, struct netif *netif))

  Adds your network interface to the netif_list. Allocate a struct
  netif and pass a pointer to this structure as the first argument.
  Give pointers to cleared ip_addr structures when using DHCP,
  or fill them with sane numbers otherwise. The state pointer may be NULL.

  The init function pointer must point to a initialization function for
  your ethernet netif interface. The following code illustrates it's use.*/
    netif_add(&xnetif, &ipaddr, &netmask, &gw, (void *)0, &ethernetif_init, ethernet_input);
    Ifx_print("net_init netif_add down \r\n");

    netif_set_up(&xnetif);

    //IfxSrc_init(&SRC_ETH_ETH0_SR, IfxSrc_Tos_cpu0, ISR_PRIORITY_ETH_IRQ);
    //IfxSrc_enable(&SRC_ETH_ETH0_SR);
    //Ifx_print("net_init netif_set_default down \r\n");
    Ifx_print("net_init down \r\n");
}

IFX_INTERRUPT(ETH_IRQHandler, 0, ISR_PRIORITY_ETH_IRQ);
void ETH_IRQHandler(void)
{
    /* Disable further ETH RX interrupts */
    if (IfxEth_isRxInterrupt(&g_drv_eth.eth))
    {
        //led_107_on();
        IfxPort_setPinState(LED1, IfxPort_State_toggled);
        IfxEth_clearRxInterrupt(&g_drv_eth.eth);
        ethernetif_poll(&xnetif);
    }
    if (IfxEth_isTxInterrupt(&g_drv_eth.eth))
    {
        led_108_on();
        IfxEth_clearTxInterrupt(&g_drv_eth.eth);
    }
    if (IfxEth_isTuInterrupt(&g_drv_eth.eth))
    {
        led_109_on();
        IfxEth_clearTuInterrupt(&g_drv_eth.eth);
    }
    IfxSrc_clearRequest(&SRC_ETH_ETH0_SR);
}

void recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *pkt_buf,
                   const ip_addr_t *addr, u16_t port)
{
    char data[100] = {0};
    Ifx_print("recv_callback in \r\n");
    /* process new connection request */
    memcpy(data, pkt_buf->payload, pkt_buf->len);
    Ifx_print("data is %s \r\n", data);
    pbuf_free(pkt_buf);
}

void vudp_send_core0(void *pvParameters)
{
    struct udp_pcb *udp;
    err_t err;
    ip_addr_t dest_addr;
    struct pbuf *ppkt_buf;
    char data_test[10] = {1};
    int n = 100000000, i = 0;

    Ifx_print("net_init no dhcp\r\n");
    net_init();

    IP4_ADDR(&dest_addr, 192, 168, 5, 196);
    udp = udp_new();

    udp_bind(udp, IP_ADDR_ANY, 0);

    err = udp_connect(udp, &dest_addr, UDP_SERVER_PORT);
    if (err != ERR_OK)
    {
        Ifx_print("udp_connect error.%x \r\n", err);
        while (1)
        {
        }
    }
    udp_recv(udp, recv_callback, NULL);
    for (;;)
    {
        i++;
        while (n--)
            ;
        n = 300000000;
        ppkt_buf = pbuf_alloc(PBUF_TRANSPORT, sizeof(data_test), PBUF_POOL);
        if (ppkt_buf != NULL)
        {

            Ifx_print("send -- %d- msg %p\r\n", i, ppkt_buf);
            memcpy(ppkt_buf->payload, data_test, sizeof(data_test));
            udp_sendto(udp, ppkt_buf, &dest_addr, UDP_SERVER_PORT);
            //System_Periodic_Handle();
            pbuf_free(ppkt_buf);
        }
    }
    udp_remove(udp);
}

int core0_main(void)
{
    IfxCpu_enableInterrupts();

    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());

    /* Initialize the LED and the time constants before the CPUs synchronization */
    init_led();
    initTime();
    init_uart_module();

    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    vudp_send_core0(NULL);

    while (1)
    {
        //led_108_blink();
    }
    return (1);
}
